package com.fz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fz.entity.Fee;
import com.fz.entity.User;
import com.fz.mapper.FeeMapper;
import com.fz.mapper.UserMapper;
import com.fz.service.FeeService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * <p>
 * 存储水电使用账单信息 服务实现类
 * </p>
 *
 * @author hyr
 * @since 2025-06-22
 */
@Service
public class FeeServiceImpl extends ServiceImpl<FeeMapper, Fee> implements FeeService {
    @Resource
    private FeeMapper feeMapper;

    @Resource
    private UserMapper userMapper;

    @Override
    public Page<Fee> listByPage(Integer pageNo, Integer pageSize, Long userId, Integer type) {
        QueryWrapper<Fee> wrapper = new QueryWrapper<>();
        if (userId != null) {
            wrapper.eq("user_id", userId);
        }
        if (type != null) {
            wrapper.eq("type", type);
        }
        wrapper.orderByDesc("create_time");
        return this.page(new Page<>(pageNo, pageSize), wrapper);
    }

    @Override
    public List<Map<String, Object>> getDailyConsumption(Long userId) {
        return feeMapper.getDailyConsumption(userId);
    }

    @Override
    public List<Map<String, Object>> getFeeDistribution(Long userId) {
        return feeMapper.getFeeDistribution(userId);
    }

    // 每天凌晨1点生成费用数据并自动扣款
    @Scheduled(cron = "0 0 1 * * ?")
    @Transactional
    @Override
    public void generateAndDeductFeeData() {
        List<User> users = userMapper.selectList(null);
        Random random = new Random();

        for (User user : users) {
            // 生成水费账单并扣款
            generateAndDeductFee(user, 1, 5 + random.nextDouble() * 10, 3.5, "water");

            // 生成电费账单并扣款
            generateAndDeductFee(user, 2, 10 + random.nextDouble() * 30, 0.6, "electricity");

            // 生成燃气费账单并扣款
            generateAndDeductFee(user, 3, 1 + random.nextDouble() * 5, 2.8, "account");
        }
    }

    private void generateAndDeductFee(User user, int type, double base, double unitPrice, String balanceField) {
        BigDecimal consumed = BigDecimal.valueOf(base).setScale(2, RoundingMode.HALF_UP);
        BigDecimal amount = consumed.multiply(BigDecimal.valueOf(unitPrice)).setScale(2, RoundingMode.HALF_UP);

        // 获取用户最新余额
        User currentUser = userMapper.selectById(user.getId());
        BigDecimal currentBalance = getBalance(currentUser, balanceField);

        Fee fee = new Fee();
        fee.setUserId(user.getId());
        fee.setType(type);
        fee.setConsumed(consumed);
        fee.setAmount(amount);
        fee.setCreateTime(LocalDateTime.now());

        if (currentBalance.compareTo(amount) >= 0) {
            // 余额足够，扣款成功
            BigDecimal newBalance = currentBalance.subtract(amount);
            setBalance(currentUser, balanceField, newBalance);
            fee.setStatus(1); // 已支付
            fee.setPaidTime(LocalDateTime.now());
        } else {
            // 余额不足，标记为待支付
            fee.setStatus(0); // 待支付
        }

        // 保存账单
        this.save(fee);

        // 更新用户余额
        if (fee.getStatus() == 1) {
            userMapper.updateById(currentUser);
        }
    }

    private BigDecimal getBalance(User user, String field) {
        switch (field) {
            case "water": return user.getWater();
            case "electricity": return user.getElectricity();
            case "account": return user.getAccount();
            default: return BigDecimal.ZERO;
        }
    }

    private void setBalance(User user, String field, BigDecimal value) {
        switch (field) {
            case "water": user.setWater(value); break;
            case "electricity": user.setElectricity(value); break;
            case "account": user.setAccount(value); break;
        }
    }
}